/*
 * Copyright (c) 2010-2011 Josef Hardi <josef.hardi@gmail.com>
 * Copyright (c) 2010 Piotr Zagawa <piotr.zagawa@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package id.duapuluhdua.dakidaki;

import java.text.DecimalFormat;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.location.Location;
import android.util.Log;

/**
 * A utility class.
 */
public class Utils
{
  /** Constants */
  private static final String TAG = "Utils";
  private static final int MAX_TIME_VALUE_24_HOURS = 3600 * 24;

  public static final double ONE_FOOT_IN_METERS = 0.3048f;
  public static final double ONE_MILE_IN_METERS = 1609.344f;
  public static final double ONE_MILE_IN_FOOTS = 5280f;

  /** Fields */
  private static String euroDistanceUnit = "m";
  private static String euroDistanceKiloUnit = "km";

  private static String usaDistanceUnit = "ft";
  private static String usaDistanceKiloUnit = "mi";

  private static DecimalFormat distanceKiloUnit = new DecimalFormat("0.00");
  private static DecimalFormat distanceUnit  = new DecimalFormat("0");

  private static DecimalFormat distanceKiloMetersInt = new DecimalFormat("0 km");
  private static DecimalFormat distanceKiloMeters = new DecimalFormat("0.00 km");
  private static DecimalFormat distanceMeters = new DecimalFormat("0 m");

  private static DecimalFormat distanceMilesInt = new DecimalFormat("0 mi");
  private static DecimalFormat distanceMiles = new DecimalFormat("0.00 mi");
  private static DecimalFormat distanceFoots = new DecimalFormat("0 ft");

  private static String time = "%d:%02d";
  private static String timeZero = "0:00";

  /**
   * Get the application version from manifest.
   *
   * @param context
   *          The application context.
   * @return Version number.
   */
  public static String getAppVersion(Context context)
  {
    final PackageManager packageManager = context.getPackageManager();
    if (packageManager != null) {
      PackageInfo packageInfo = null;
      try {
        packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
        if (packageInfo != null) {
          return packageInfo.versionName;
        }
      }
      catch (NameNotFoundException e) {
        Log.e(TAG, e.getMessage());
      }
    }
    return "";
  }

  public static String getLongitudeAsString(double lon)
  {
    String lonStr = Location.convert(lon, Location.FORMAT_SECONDS);
    lonStr += (lon >= 0) ? " E" : " W";
    return lonStr;
  }

  public static String getLatitudeAsString(double lat)
  {
    String latStr = Location.convert(lat, Location.FORMAT_SECONDS);
    latStr += (lat >= 0) ? " N" : " S";
    return latStr;
  }

  /**
   * Return the distance unit according to the measurement standard (EU or US).
   *
   * @param prefs
   *          The general preference.
   * @param distance
   *          The distance number.
   * @return The distance string with its unit.
   */
  public static String getDistance(Preferences prefs, double distance)
  {
    final int mode = prefs.measureMode;
    String value = "--";

    switch(mode)
    {
      case Preferences.MEASURE_MODE_EU:
        value = distanceMeters.format(distance);  // in meters
        break;

      case Preferences.MEASURE_MODE_USA:
        value = distanceMiles.format(metersToMiles(distance));  // in miles
        break;
    }
    return value;
  }

  public static String getDistanceInt(Preferences prefs, int distance)
  {
    final int mode = prefs.measureMode;
    String value = "--";

    switch(mode)
    {
      case Preferences.MEASURE_MODE_EU:
        value = distanceKiloMetersInt.format(distance / 1000);
        break;

      case Preferences.MEASURE_MODE_USA:
        value = distanceMilesInt.format(metersToMiles(distance));
        break;
    }
    return value;
  }

  public static String getPreciseDistance(Preferences prefs, double distance)
  {
    final int mode = prefs.measureMode;
    String value = "--";

    switch(mode)
    {
      case Preferences.MEASURE_MODE_EU:
        value = distanceMeters.format(distance);  // in meters
        if (distance > 10000) {
          value = distanceKiloMeters.format(distance / 1000);
        }
        break;

      case Preferences.MEASURE_MODE_USA:
        value = distanceFoots.format(metersToFoots(distance)); // in feet
        if (distance > ONE_MILE_IN_METERS) {
          distanceMiles.format(metersToMiles(distance));
        }
        break;
    }
    return value;
  }

  /**
   * Convert distance in meters to value
   *
   * @param prefs
   * @param distance
   * @return
   */
  public static String getPreciseDistanceValue(Preferences prefs, double distance)
  {
    final int mode = prefs.measureMode;
    String value = "--";

    switch(mode)
    {
      case Preferences.MEASURE_MODE_EU:
        value = distanceUnit.format(distance);
        if (distance > 10000) {
          distanceKiloUnit.format(distance / 1000);
        }
        break;

      case Preferences.MEASURE_MODE_USA:
        value = distanceUnit.format(metersToFoots(distance));
        if (distance > ONE_MILE_IN_METERS) {
          distanceKiloUnit.format(metersToMiles(distance));
        }
        break;
    }
    return value;
  }

  /**
   * Get distance unit.
   *
   * @param prefs
   * @param distance
   * @return
   */
  public static String getDistanceUnit(Preferences prefs, double distance)
  {
    final int mode = prefs.measureMode;
    String value = "";

    switch(mode)
    {
      case Preferences.MEASURE_MODE_EU:
        value = euroDistanceUnit;
        if (distance > 10000) {
          value = euroDistanceKiloUnit;
        }
        break;

      case Preferences.MEASURE_MODE_USA:
        value = usaDistanceUnit;
        if (distance > ONE_MILE_IN_METERS) {
          value = usaDistanceKiloUnit;
        }
        break;
    }
    return value;
  }

  public static String getTime(int seconds)
  {
    if (seconds < 0) {
      return "";
    }
    if (seconds > MAX_TIME_VALUE_24_HOURS) {
      return "";
    }

    final int hours = (int) (seconds / 3600.0f);
    final int minutes = (int) ((seconds / 60.0f) % 60);

    return String.format(time, hours, minutes);
  }

  /**
   * Meter to mile conversion.
   *
   * @param meters
   *          distance in meters.
   * @return distance in miles.
   */
  public static double metersToMiles(double meters)
  {
    return meters / ONE_MILE_IN_METERS;
  }

  public static double metersToFoots(double meters)
  {
    return meters / ONE_FOOT_IN_METERS;
  }

  public static double milesToMeters(double miles)
  {
    return miles * ONE_MILE_IN_METERS;
  }

  public static double footsToMeters(double foots)
  {
    return foots * ONE_FOOT_IN_METERS;
  }
}
